#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <errno.h>
#include "client.h"

// 全局会话变量
client_session_t g_session;
volatile sig_atomic_t g_running = 1;

// 信号处理函数
void signal_handler(int sig)
{
    if (sig == SIGINT || sig == SIGTERM)
    {
        fprintf(stderr, "\n接收到终止信号 (%d)，g_running即将被设置为0，准备关闭客户端...\n", sig);
        g_running = 0;
    }
}

// 显示帮助信息
void show_usage(const char *prog_name)
{
    printf("用法: %s [选项]\n", prog_name);
    printf("选项:\n");
    printf("  -h, --host <主机名>     指定服务器主机名或IP地址 (默认: localhost)\n");
    printf("  -p, --port <端口>       指定服务器端口 (默认: 8888)\n");
    printf("  -?, --help              显示帮助信息\n");
}

// 交互式菜单
void show_menu()
{
    printf("\n====== 安全文件传输系统 客户端 ======\n");
    printf("1. 注册新用户\n");
    printf("2. 登录\n");
    printf("3. 上传文件\n");
    printf("4. 下载文件\n");
    printf("5. 列出文件\n");
    printf("6. 删除文件\n");
    printf("7. 退出\n");
    printf("请选择操作 (1-7): ");
    fflush(stdout);
}

// 注册新用户
void register_user()
{
    char username[256];
    char password[256];

    printf("\n=== 用户注册 ===\n");
    printf("用户名: ");
    fgets(username, sizeof(username), stdin);
    username[strcspn(username, "\n")] = 0;

    printf("密码: ");
    fgets(password, sizeof(password), stdin);
    password[strcspn(password, "\n")] = 0;

    int result = client_register(&g_session, username, password);
    if (result == 0)
    {
        printf("注册成功!\n");
    }
    else
    {
        printf("注册失败: %d\n", result);
    }
}

// 用户登录
void login()
{
    char username[256];
    char password[256];

    printf("\n=== 用户登录 ===\n");
    printf("用户名: ");
    fgets(username, sizeof(username), stdin);
    username[strcspn(username, "\n")] = 0;

    printf("密码: ");
    fgets(password, sizeof(password), stdin);
    password[strcspn(password, "\n")] = 0;

    int user_id_returned = client_authenticate(&g_session, username, password);
    if (user_id_returned > 0)
    { // client_authenticate returns user_id (>0) on success
        // g_session.user_id is already set by client_authenticate on success
        printf("登录成功! 用户ID: %d\n", g_session.user_id);
    }
    else
    { // result is -1 (failure, client_authenticate prints details)
        printf("登录操作完成但未成功 (详情见上条错误信息)。\n");
    }
}

// 上传文件
void upload_file()
{
    char local_path[1024];
    char remote_path[1024];

    printf("\n=== 上传文件 ===\n");
    printf("本地文件路径: ");
    fgets(local_path, sizeof(local_path), stdin);
    local_path[strcspn(local_path, "\n")] = 0;

    printf("远程文件名: ");
    fgets(remote_path, sizeof(remote_path), stdin);
    remote_path[strcspn(remote_path, "\n")] = 0;

    printf("正在上传文件 %s -> %s...\n", local_path, remote_path);
    int result = client_upload_file(&g_session, local_path, remote_path);
    if (result == 0)
    {
        printf("文件上传成功!\n");
    }
    else
    {
        printf("文件上传失败: %d\n", result);
    }
}

// 下载文件
void download_file()
{
    char remote_path[1024];
    char local_path[1024];

    printf("\n=== 下载文件 ===\n");
    printf("远程文件名: ");
    fgets(remote_path, sizeof(remote_path), stdin);
    remote_path[strcspn(remote_path, "\n")] = 0;

    printf("本地保存路径: ");
    fgets(local_path, sizeof(local_path), stdin);
    local_path[strcspn(local_path, "\n")] = 0;

    printf("正在下载文件 %s -> %s...\n", remote_path, local_path);
    int result = client_download_file(&g_session, remote_path, local_path);
    if (result == 0)
    {
        printf("文件下载成功!\n");
    }
    else
    {
        printf("文件下载失败: %d\n", result);
    }
}

// 列出文件
void list_files()
{
    void *file_list = NULL;
    int file_count = 0;

    printf("\n=== 文件列表 ===\n");
    int result = client_get_file_list(&g_session, "/", &file_list, &file_count);
    if (result == 0 && file_list != NULL)
    {
        printf("找到 %d 个文件:\n", file_count);

        file_info_t *files = (file_info_t *)file_list;
        for (int i = 0; i < file_count; i++)
        {
            printf("[%d] %s (%llu 字节)\n", i + 1, files[i].filename,
                   (unsigned long long)files[i].size);
        }

        free(file_list);
    }
    else
    {
        printf("获取文件列表失败: %d\n", result);
    }
}

// 删除文件
void delete_file()
{
    char remote_path[1024];

    printf("\n=== 删除文件 ===\n");
    printf("文件名: ");
    fgets(remote_path, sizeof(remote_path), stdin);
    remote_path[strcspn(remote_path, "\n")] = 0;

    printf("正在删除文件 %s...\n", remote_path);
    int result = client_delete_file(&g_session, remote_path);
    if (result == 0)
    {
        printf("文件删除成功!\n");
    }
    else
    {
        printf("文件删除失败: %d\n", result);
    }
}

int main(int argc, char *argv[])
{
    char host[256] = "127.0.0.1";
    int port = 8888;

    // 解析命令行参数
    static struct option long_options[] = {
        {"host", required_argument, NULL, 'h'},
        {"port", required_argument, NULL, 'p'},
        {"help", no_argument, NULL, '?'},
        {NULL, 0, NULL, 0}};

    int option;
    int option_index = 0;
    while ((option = getopt_long(argc, argv, "h:p:?", long_options, &option_index)) != -1)
    {
        switch (option)
        {
        case 'h':
            strncpy(host, optarg, sizeof(host) - 1);
            break;
        case 'p':
            port = atoi(optarg);
            break;
        case '?':
            show_usage(argv[0]);
            return 0;
        default:
            return -1;
        }
    }

    // 设置信号处理
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    if (sigaction(SIGINT, &sa, NULL) == -1)
    {
        perror("sigaction(SIGINT) failed");
        return -1;
    }
    if (sigaction(SIGTERM, &sa, NULL) == -1)
    {
        perror("sigaction(SIGTERM) failed");
        return -1;
    }

    // 初始化客户端
    if (client_init() != 0)
    {
        fprintf(stderr, "客户端初始化失败\n");
        return -1;
    }

    // 初始化会话
    if (client_session_init(&g_session) != 0)
    {
        fprintf(stderr, "会话初始化失败\n");
        return -1;
    }

    printf("正在连接到服务器 %s:%d...\n", host, port);
    if (client_connect(&g_session, host, port) != 0)
    {
        fprintf(stderr, "连接服务器失败\n");
        client_cleanup();
        return 1;
    }
    printf("成功连接到服务器。\n");

    // 执行密钥交换
    printf("正在执行密钥交换...\n");
    if (client_key_exchange(&g_session) != 0)
    {
        fprintf(stderr, "密钥交换失败! 无法继续操作。\n");
        client_disconnect(&g_session); // 断开连接
        client_cleanup();
        return 1;
    }
    printf("密钥交换成功。\n");

    // Clear any pending input after key exchange
    fprintf(stdout, "按回车键继续...");
    fflush(stdout);
    char temp_buffer_after_connect[128];
    if (fgets(temp_buffer_after_connect, sizeof(temp_buffer_after_connect), stdin) == NULL)
    {
        if (!g_running)
        { // Check if Ctrl+C was pressed during this fgets
            fprintf(stderr, "\n关机信号在 fgets 清理缓冲区时收到. 主循环可能不会启动.\n");
        }
        else
        {
            fprintf(stderr, "\n清理缓冲区时 fgets 返回 null (EOF 或其他错误).\n");
            // This might be an EOF if input is redirected. If so, allow graceful exit.
            if (feof(stdin))
                g_running = 0;
        }
    }

    // 交互式循环
    while (g_running)
    {
        show_menu();
        char choice_str[10];
        if (fgets(choice_str, sizeof(choice_str), stdin) == NULL)
        {
            if (!g_running)
            { // Signal handler set g_running to 0 during fgets
                fprintf(stderr, "\nfgets读取选项时被信号中断 (g_running=0). 准备退出循环.\n");
                break;
            }
            // If g_running is still 1, it's a genuine EOF or other I/O error
            if (feof(stdin))
            {
                fprintf(stderr, "\n检测到标准输入EOF. 准备退出.\n");
                g_running = 0; // Ensure loop terminates
                break;
            }
            else if (ferror(stdin))
            {
                // If errno is EINTR, it means a signal (possibly not ours) interrupted.
                // If it was our signal, g_running would be 0 and caught above.
                if (errno == EINTR)
                {
                    fprintf(stderr, "\nfgets因EINTR返回NULL但g_running仍为1. 清除错误并继续...\n");
                    clearerr(stdin); // Clear error flags for next attempt
                    continue;
                }
                else
                {
                    perror("\nfgets读取选项时发生其他错误");
                    g_running = 0; // Terminate on other errors
                    break;
                }
            }
            else
            {
                fprintf(stderr, "\nfgets返回NULL但未设置EOF或错误标志. 准备退出.\n");
                g_running = 0; // Terminate on this unexpected condition
                break;
            }
        }

        // If fgets succeeded but g_running became 0 (e.g. signal during very short processing window)
        if (!g_running)
        {
            fprintf(stderr, "\n读取选项后检测到关机信号 (g_running=0). 准备退出循环.\n");
            break;
        }

        int choice = atoi(choice_str);
        // Input validation for choice can be added here if needed (e.g. is it a number, in range?)

        switch (choice)
        {
        case 1:
            register_user();
            break;
        case 2:
            login();
            break;
        case 3:
            upload_file();
            break;
        case 4:
            download_file();
            break;
        case 5:
            list_files();
            break;
        case 6:
            delete_file();
            break;
        case 7:
            printf("选择退出程序...\n");
            g_running = 0;
            break;
        default:
            printf("无效选项，请重新选择\n");
            break;
        }

        // Final check in the loop before iterating again
        if (!g_running)
        {
            break;
        }
    }

    // 清理工作
    printf("正在断开与服务器的连接...\n");
    if (g_session.sock != -1)
    { // Only disconnect if connected
        client_disconnect(&g_session);
    }
    client_cleanup();
    printf("客户端已退出。\n");

    return 0;
}